use crate::rtmp::relay::errors::ClientError;
use crate::rtmp::session::client_session::{ClientSession, ClientSessionType};
use streamhub::define::{BroadcastEvent, BroadcastEventReceiver, StreamHubEventSender};
use streamhub::stream::StreamIdentifier;
use tokio::net::TcpStream;

// 推流客户端结构体
pub struct PushClient {
    // 服务器的地址
    address: String,
    // 接收广播事件的接收器
    client_event_consumer: BroadcastEventReceiver,
    // 发送流中心事件的发送器
    channel_event_producer: StreamHubEventSender,
}

impl PushClient {
    pub fn new(
        address: String,
        consumer: BroadcastEventReceiver,
        producer: StreamHubEventSender,
    ) -> Self {
        Self {
            address,
            client_event_consumer: consumer,
            channel_event_producer: producer,
        }
    }

    // 运行推流客户端
    pub async fn run(&mut self) -> Result<(), ClientError> {
        log::info!("push client start...");

        // 进入一个无限循环，持续处理事件
        loop {
            // 异步接收一个广播事件
            let val = self.client_event_consumer.recv().await?;

            // 模式匹配接收到的广播事件
            match val {
                // 处理发布事件
                BroadcastEvent::Publish { identifier } => {
                    // 模式匹配流标识符的类型
                    if let StreamIdentifier::Rtmp {
                        app_name,
                        stream_name,
                    } = identifier
                    {
                        // 记录日志，输出要发布的应用名、流名和服务器地址
                        log::info!(
                            "publish app_name: {} stream_name: {} address: {}",
                            app_name.clone(),
                            stream_name.clone(),
                            self.address.clone()
                        );
                        // 异步连接到指定地址的服务器，如果连接过程中出现错误，会将错误转换为 ClientError 并返回
                        let stream = TcpStream::connect(self.address.clone()).await?;

                        // 创建一个新的 ClientSession 实例，类型为 Push
                        let mut client_session = ClientSession::new(
                            stream,
                            ClientSessionType::Push,
                            self.address.clone(),
                            app_name,
                            stream_name,
                            self.channel_event_producer.clone(),
                            0,
                        );

                        // 使用 tokio 异步执行器生成一个新的任务，在后台运行客户端会话
                        tokio::spawn(async move {
                            // 调用客户端会话的 start 方法，如果运行过程中出现错误，记录错误日志
                            if let Err(err) = client_session.run().await {
                                log::error!("client_session as push client start error: {}", err);
                            }
                        });
                    }
                }
                // 处理其他类型的事件
                _ => {
                    log::info!("push client receive other events");
                }
            }
        }
    }
}
